/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 文件名：	DefaultUpgradeSearcher.java
 * 模块说明：	
 * 修改历史：
 * Dec 7, 2007 - zhangyanbo - 创建。
 */
package com.hd123.rumba.upgrade.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import com.hd123.rumba.cartridge.biz.BCartridge;
import com.hd123.rumba.cartridge.biz.IBCartridgeMgr;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.upgrade.IUpgradeSearcher;
import com.hd123.rumba.upgrade.Upgrade;
import com.hd123.rumba.util.Version;

/**
 * @author zhangyanbo
 * 
 */
public class UpgradeSearcher implements IUpgradeSearcher {

  public List<Upgrade> search() throws BusinessException {
    Logger logger = Logger.getLogger(this.getClass());
    List<Upgrade> upgrades = new ArrayList<Upgrade>();
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);
    List<BCartridge> cartridges = cartMgr.getAllCartridges();
    cartridges = analyzeDependencies(cartridges);
    for (BCartridge cart : cartridges) {
      logger.info("搜索构件包(" + cart.getClass().getName() + ")的升级包...");
      upgrades.addAll(search(cart));
    }
    return upgrades;
  }

  private List<BCartridge> analyzeDependencies(List<BCartridge> cartridges)
      throws BusinessException {
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);
    List<BCartridge> carts = new ArrayList<BCartridge>();
    try {
      IDependencyAnalyzer da = new DependencyAnalyzer();
      for (BCartridge cart : cartridges) {
        if (cart.getReferences().size() == 0)
          da.addDependency(cart.getUuid(), null);
        else {
          for (int i = 0; i < cart.getReferences().size(); i++) {
            String refCartPrefix = cart.getReferences().get(i).getRefCartPrefix();
            String refCartUuid = cartMgr.getCartridgeByPrefix(refCartPrefix).getUuid();
            da.addDependency(cart.getUuid(), refCartUuid);
          }
        }
      }
      List<String> cartUuids = da.getSortedIds();
      for (String cartUuid : cartUuids)
        for (BCartridge cart : cartridges) {
          if (cart.getUuid().equals(cartUuid)) {
            carts.add(cart);
            break;
          }
        }
    } catch (Exception e) {
      throw new BusinessException(e);
    }
    return carts;
  }

  private List<Upgrade> search(BCartridge cart) throws BusinessException {
    IBCartridgeMgr cartMgr = (IBCartridgeMgr) NamingMgr.getInstance().lookupMgr(
        IBCartridgeMgr.class);
    Version appVersion = cart.getVersion().truncate(3);
    Version dbVersion = cartMgr.getDBVersion(cart.getUuid()).truncate(3);
    if (dbVersion.compareTo(appVersion) > 0)
      throw new BusinessException("应用程序版本(" + appVersion.toString() + ")低于当前已安装版本("
          + dbVersion.toString() + ")，不能进行升级。");
    else if (dbVersion.compareTo(appVersion) == 0)
      return new ArrayList<Upgrade>();

    List<Upgrade> upgrades = searchUpgrades(cart);
    List<Upgrade> result = new ArrayList<Upgrade>();
    List<String> versions = null;
    IPathSearcher ps = new OptimalPathSearcher();
    try {
      for (Upgrade u : upgrades)
        ps.addEdge(u.getBaseVersion().truncate(3).toString(), u.getTargetVersion().truncate(3)
            .toString());
      versions = ps.search(dbVersion.truncate(3).toString(), appVersion.truncate(3).toString());
    } catch (Exception e) {
      throw new BusinessException(e);
    }
    if (versions == null)
      throw new BusinessException("找不到从 " + dbVersion.toString() + " 升级到 " + appVersion.toString()
          + " 的升级包。");
    for (int i = 0; i < versions.size() - 1; i++)
      for (Upgrade u : upgrades)
        if (u.getBaseVersion().truncate(3).toString().equals(versions.get(i))
            && u.getTargetVersion().truncate(3).toString().equals(versions.get(i + 1))) {
          result.add(u);
          break;
        }

    return result;
  }

  private List<Upgrade> searchUpgrades(BCartridge cart) throws BusinessException {
    List<Upgrade> upgrades = new ArrayList<Upgrade>();
    for (String className : cart.getUpgradeClassNames())
      try {
        upgrades.add((Upgrade) Class.forName(className).newInstance());
      } catch (Exception e) {
        throw new BusinessException(e);
      }
    return upgrades;
  }
}
